package com.personal.core.xml;

import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class XMLDocument
{
    private Document doc;

    public Element initRoot(String rootName)
    {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = null;
        try
        {
            builder = factory.newDocumentBuilder();
        }
        catch (ParserConfigurationException e)
        {
            return null;
        }

        doc = builder.newDocument();

        Element e = doc.createElement(rootName);

        doc.appendChild(e);

        return e;
    }

    /**
     * @param node node
     * @param xpath xpath
     * @return Element
     */
    public Element getElementByXpath(Element node, String xpath)
    {
        String[] pathArray = xpath.split("/");

        for (String path : pathArray)
        {
            node = this.getElement(node, path);

            if (node == null)
            {
                return null;
            }
        }

        return node;
    }

    private Element getElement(Element node, String xpath)
    {
        NodeList list = node.getChildNodes();
        if (list == null)
        {
            return null;
        }
        if (list.getLength() <= 0)
        {
            return null;
        }
        for (int i = 0; i < list.getLength(); i++)
        {
            if (list.item(i) instanceof Element)
            {
                if (list.item(i).getNodeName().equals(xpath))
                {
                    return (Element) list.item(i);
                }
            }
        }

        return null;
    }

    /**
     * @param xpath xpath
     * @return Node
     */
    public Node getElement(String xpath)
    {
        NodeList list = doc.getDocumentElement().getChildNodes();
        if (list == null)
        {
            return null;
        }
        if (list.getLength() <= 0)
        {
            return null;
        }
        return list.item(0);
    }

    /**
     * ��ȡ��ڵ�
     * @return Element
     */
    public Element getRootElement()
    {
        if (doc == null)
        {
            return null;
        }
        return doc.getDocumentElement();
    }

    /**
     * ��ȡ�ӽڵ㼯��
     * @param e �ڵ�
     * @return list
     */
    public List<Element> getChildList(Element e)
    {
        List<Element> childs = new ArrayList<Element>();
        if (doc == null)
        {
            return childs;
        }
        NodeList list = e.getChildNodes();
        for (int i = 0; i < list.getLength(); i++)
        {
            if (list.item(i) instanceof Element)
            {
                childs.add((Element) list.item(i));
            }
        }

        return childs;
    }

    /**
     * ���ļ�����Ϊ�ڴ�XML����
     * @param path �ļ�·��
     * @throws Exception ��ʼ��ʧ��
     */
    public void loadFromFile(String path) throws Exception
    {
        try
        {
            FileInputStream stream = new FileInputStream(path);
            this.load(stream);
        }
        catch (Exception e)
        {
            throw new Exception("��ʼ�� XML �ļ�ʧ�ܣ�");
        }
    }

    /**
     * �� XML �ַ����Ϊ�ڴ����
     * @param xml XML�ַ�
     * @throws Exception ��ʼ��ʧ��
     */
    public void loadFromXml(String xml) throws Exception
    {
        try
        {
            ByteArrayInputStream stream = new ByteArrayInputStream(xml.getBytes("utf-8"));
            this.load(stream);
        }
        catch (Exception e)
        {
            throw new Exception("��ʼ�� XML �ļ�ʧ�ܣ�");
        }
    }

    /**
     * @param stream stream
     * @throws Exception Exception
     */
    public void load(InputStream stream) throws Exception
    {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();

        doc = builder.parse(stream);
        doc.normalize();
    }

    /**
     * ��ݸ��ڵ㴴���ӽڵ�
     * @param parentNode ���ڵ�
     * @param childName �ӽڵ����
     * @param childValue �ӽڵ�ֵ
     * @return Element
     */
    public Element apendChildNode(Element parentNode, String childName, String childValue)
    {
        if (doc == null)
        {
            return null;
        }
        Element child = doc.createElement(childName);
        child.setTextContent(childValue);

        parentNode.appendChild(child);

        return child;
    }

    /**
     * ��ĳ��ڵ��������
     * @param node �ڵ�
     * @param attrName ������
     * @param attrValue ����ֵ
     * @return ��ӳɹ������Զ���
     */
    public Attr apendNodeAttr(Element node, String attrName, String attrValue)
    {
        if (doc == null)
        {
            return null;
        }
        Attr attr = doc.createAttribute(attrName);
        attr.setTextContent(attrValue);

        node.setAttributeNode(attr);

        return attr;
    }

    /**
     * ����ǰXML�ڴ�������Ϊ XML �ַ�
     * @throws IOException IOException
     * @return XML �ַ�
     */
    public String asXML() throws IOException
    {
        StringWriter out = new StringWriter();
        XMLWriter writer = new XMLWriter(out);
        try
        {
            writer.writeNode(doc.getDocumentElement());
            writer.flush();
        }
        catch (Exception e)
        {
            return "";
        }
        return out.toString();
    }

}
